#include "TextClassifier.h"
#include "StringUtil.h"
SK

TextClassifier::TextClassifier ()
{
    textNet = new NeuralNet (1,16,4, 16, 0.1f);
}

TextClassifier::~TextClassifier ()
{
    delete textNet;
}


void TextClassifier::loadLexicon (const String& filePath)
{
    FileStream fle;
	fle.open(filePath.c_str());

    while (fle.good())
    {
        String line;

		std::getline(fle, line);
        int commaLoc = line.find (',');

        if (commaLoc == String::npos)
            continue;

        String word = line.substr (0, commaLoc);
        u32 id = StringUtil::parseUInt (line.substr (commaLoc+1));
        lex.insert (Lexicon::value_type (word, id));
    }

    fle.close();
}

void TextClassifier::saveLexicon (const String& filePath)
{
    FileStream fle;
	fle.open (filePath.c_str());
    Lexicon::iterator it;

    for (it = lex.begin(); it != lex.end(); it++)
        fle << (*it).first << "," << (*it).second << std::endl;

    fle.close();
}

u32 TextClassifier::getLexID (const String& word)
{
	Lexicon::iterator it = lex.find (word);

	if (it == lex.end())
		return 0;
	else
		return (*it).second;
}

void TextClassifier::readTrainingDocument (const String& path, u32 iterations)
{
    for (u32 i=0; i<iterations; i++)
	{
		FileStream fle;
		fle.open (path.c_str());
		u32 curPos=0;

		TokenInfo prevToken;
		TokenInfo curToken;
		TokenInfo nextToken;

		prevToken.id=0;
		prevToken.type = WORD_SENTENCESTART;
		curToken.id=0;
		curToken.type = WORD_SENTENCESTART;

		REAL inputs [4];
		REAL outputs [16];

		while (fle.good())
		{
			String line;
			std::getline (fle, line);

			int colLoc = line.find (':');
			if (colLoc == String::npos)
				continue;

			nextToken.id = getLexID (line.substr (0, colLoc));
			nextToken.type = (WordClass)StringUtil::parseUInt (line.substr (colLoc+1));
		
			if (curToken.type == WORD_SENTENCESTART)
			{
				curToken.id = nextToken.id;
				curToken.type = nextToken.type;
				curPos++;
				continue;
			}

			inputs [0] = (REAL)prevToken.id;
			inputs [1] = (REAL)curToken.id;
			inputs [2] = (REAL)nextToken.id;
			inputs [3] = (REAL)curPos;
			memset ((void *)outputs, 0, sizeof (REAL) * 16);
			outputs [(u32)curToken.type] = 1.0f;

			textNet->setInput (inputs);
			textNet->train (outputs);

			if (curToken.type == WORD_PERIOD || curToken.type == WORD_QUESTIONMARK || curToken.type == WORD_EXCLEMATION)
			{
				prevToken.id=0;
				prevToken.type = WORD_SENTENCESTART;
				curToken.id=0;
				curToken.type = WORD_SENTENCESTART;
				curPos=0;
				continue;
			}

			curToken.id = nextToken.id;
			curToken.type = nextToken.type;
			curPos++;
		}
	}
}

WordClass TextClassifier::classify (const String& word,const String& previousWord, const String& nextWord, u32 sentencePos)
{
	REAL inputs [4];

	u32 curWord = getLexID (word);
	u32 prevWord = getLexID (previousWord);
	u32 nxtWord = getLexID (nextWord);

	inputs [0] = (REAL)prevWord;
	inputs [1] = (REAL)curWord;
	inputs [2] = (REAL)nxtWord;
	inputs [3] = (REAL)sentencePos;

	textNet->setInput (inputs);
	textNet->run ();
	REAL *out = textNet->getOutput();
	u32 maxID=0;
	REAL curMax = 0.0f;

	for (u32 i=0; i<16; i++)
	{
		if (out [i] > curMax)
		{
			curMax = out [i];
			maxID = i;
		}
	}

	return (WordClass)maxID;
}

EK